package domainhandler.smtp;

import http.HTTPConnection;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.httpclient.NameValuePair;
import org.grlea.log.SimpleLogger;

import domainhandler.IDomainHandler;

import exception.LoginException;

import pattern.YahooPatterns;
import util.NCRDecoder;
import util.yahoo.FolderDigester;
import util.yahoo.ListMessagesDigester;
import util.yahoo.MessageBodyDigester;
import util.yahoo.MessageHeaderDigester;
import vo.IListMessageResponse;
import vo.yahoo.Folder;
import vo.yahoo.Folders;
import vo.yahoo.ListMessageResponse;
import vo.yahoo.Message;
import vo.yahoo.MessageInfo;
import vo.yahoo.MessagePart;

public class YahooBetaHandler implements IDomainHandler{

	private static final SimpleLogger log = new SimpleLogger(YahooBetaHandler.class);
//	// list of folders
//	private List folders = null ;
//	// private mailbox URL
	private String baseURL = null ;
//	// wssid for next calls.
	private String wssid = null ;
	// parsed resposne from ListMessage SoapCall
	ListMessageResponse listMessageResponse = null ;
//	// raw headers from the message
//	String rawHeaders = null ;
//	// envelope headers for the message
//	String envelopeHeaders = null ;
//	// current message
//	Message message = null ;
//	
	// TODO: change this to get from user.. 
//	private Set subscribedFolders = new HashSet() ;
	public YahooBetaHandler() {
//		subscribedFolders.add("Inbox");
//		subscribedFolders.add("Nikhil");
	}
	
	
	public void logIn(String username, String password) throws LoginException{
		log.debug("enteres");
		URL url = null;
		try {
			url = new URL("http://mail.yahoo.com");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		StringBuffer response = HTTPConnection.getInstance().connect(url, null, "GET", "application/x-www-form-urlencoded");
		StringBuffer loginForm = null ;
		try{
			loginForm = (StringBuffer) matcher(YahooPatterns.patternYahooLoginForm,response).get(0);
		}catch(IndexOutOfBoundsException ioe){
			// something went wrong again :-(
			throw new LoginException();
		}
//		log.debug("loginFrom: "+loginForm);
		StringBuffer loginAction = (StringBuffer) matcher(YahooPatterns.patternYahooAction, loginForm).get(0);
		log.debug("loginAction: "+loginAction.toString());
		loginAction = (StringBuffer) matcher("action=\"(.*?)\"", loginAction).get(0);
		String loginUrl = loginAction.substring(loginAction.indexOf("\"")+1, loginAction.lastIndexOf("\""));
		log.debug("url: "+loginUrl);
		List inputFields = matcher(YahooPatterns.patternYahooInput, loginForm);
		log.debug(""+inputFields.size());
		// form the data to be sent to the server:
//		List requestParams = new  ArrayList(10);
		NameValuePair [] requestParams = new NameValuePair[inputFields.size()+3];
		for (int i = 0 ; i < inputFields.size(); i++) {
			StringBuffer inputField = (StringBuffer) inputFields.get(i);
			StringBuffer name = (StringBuffer) matcher("name=\".*?\"",inputField).get(0);
			String key = name.substring(name.indexOf("\"")+1, name.lastIndexOf("\""));
			StringBuffer value = (StringBuffer) matcher("value=\".*?\"",inputField).get(0);
//				log.debug("val"+value);
			String val = value.substring(value.indexOf("\"")+1, value.lastIndexOf("\""));
			requestParams[i] = new NameValuePair(key,val);
		}
		requestParams[inputFields.size()] = new NameValuePair("login",username);
		requestParams[inputFields.size()+1] = new NameValuePair("passwd", password);
		requestParams[inputFields.size()+2] = new NameValuePair(".persistent", "y");
//		log.debug(requestParams.toString());
//		all set! now make a call
		url = null;
		try {
			url = new URL(loginUrl);
			System.out.println(url.getHost());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		StringBuffer loginResponse = HTTPConnection.getInstance().connect(url, requestParams, "POST", "application/x-www-form-urlencoded");
//		log.debug(loginResponse.toString());
		
		// extract the real url to make the call
		StringBuffer mainFormStr = (StringBuffer) matcher(YahooPatterns.patternYahooMainWindow,loginResponse).get(0);
//		log.debug("mainFormStr: "+mainFormStr);
		String mainForm = mainFormStr.substring(mainFormStr.indexOf("\"")+1, mainFormStr.length()-1);
//		log.debug("mainForm: "+mainForm);
		
		url = null;
		try {
			url = new URL(mainForm);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		StringBuffer mainResponse = HTTPConnection.getInstance().connect(url, null, "GET", "application/x-www-form-urlencoded");
//		log.debug(mainResponse.toString());
		
		// now we have logged in main form of Yahoo beta mail!
		StringBuffer sbWssid = null ;
		try{
			sbWssid = (StringBuffer) matcher(YahooPatterns.kPatternWssid,mainResponse).get(0);
		}catch(IndexOutOfBoundsException ioe){
			// that means your login has not succeeded!
			throw new LoginException();
		}
		String wssid = sbWssid.substring(sbWssid.indexOf("'")+1, sbWssid.length()-1);
		log.debug("wssid: "+wssid.toString());

		
		this.setWssid(wssid);
		// cool make the soap call to get folder list
		this.setBaseURL(url.getProtocol()+"://"+url.getHost());
		
		
//		try {
//			url = new URL(this.getBaseURL()+YahooPatterns.soapListFolders+wssid);
//		} catch (MalformedURLException e) {
//			e.printStackTrace();
//		}
		
//		requestParams = new NameValuePair[]{
//				new NameValuePair("",YahooPatterns.kListFolders)};
//		StringBuffer soapFolderResponse = HTTPConnection.getInstance().connect(url, requestParams, "POST","application/xml");
//		log.debug(soapFolderResponse.toString());
		
		// process the folder list
		// TODO in future to handle various folders
//		setFolders(((Folders) FolderDigester.parse(soapFolderResponse.toString())).getFolderList());

		
//		StringBuffer folderData = (StringBuffer) matcher(YahooPatterns.kPatternFolderResponse,soapFolderResponse).get(0);
//		log.debug("folderData: "+folderData);
//		StringBuffer folderData = (StringBuffer) matcher(YahooPatterns.kPatternFolderResponse,soapFolderResponse).get(0);
//		log.debug("folderData: "+folderData);
//		String mainForm = mainFormStr.substring(mainFormStr.indexOf("\"")+1, mainFormStr.length()-1);
		
		
	}
	public static void main(String[] args) throws LoginException {
		YahooBetaHandler y = new YahooBetaHandler();
		y.logIn("test", "test");
	}
	
	public List matcher(String patternString, StringBuffer searchString){
		Pattern pattern = Pattern.compile(patternString);
		Matcher matcher = pattern.matcher(searchString);
		List matcherGroup = new ArrayList() ;
//		int i = 0;
        while (matcher.find()){
        	matcherGroup.add(new StringBuffer(matcher.group()));
        }
		return matcherGroup ;
	}
//	public List getFolders() {
//		return folders;
//	}
//	public void setFolders(List folders) {
//		this.folders = folders;
//	}
	
	public String getStats() {
//		// find out which all folders are requested for the stat
//		List foldersForStat = new ArrayList();
//		for (Iterator iter = getFolders().iterator(); iter.hasNext();) {
//			Folder folder = (Folder) iter.next();
//			if(getSubscribedFolders().contains(folder.getName())){
//				foldersForStat.add(folder.getName());
//			}
//		}
//		log.debug("folders for Stat: "+foldersForStat);
//		for (Iterator iter = foldersForStat.iterator(); iter.hasNext();) {
//			String folderName = (String) iter.next();
////			 get the stat for each folder
//			log.debug("baseUrl: "+getBaseURL());
//			log.debug("wssid: "+getWssid());
//			log.debug("kListMsg: "+YahooPatterns.kListMsgs);
//			URL url = null ;
//			try {
//				url = new URL(this.getBaseURL()+YahooPatterns.soapListMessages+wssid);
//			} catch (MalformedURLException e) {
//				e.printStackTrace();
//			}
//			
//			NameValuePair [] requestParams = new NameValuePair[]{
//					new NameValuePair("",YahooPatterns.kListMsgs.replace("folderName", folderName))};
//			StringBuffer soapListMessageResponse = HTTPConnection.getInstance().connect(url, requestParams, "POST","application/xml");
//			log.debug(soapListMessageResponse.toString());
//	
//			// process the folder list
//			setListMessageResponse((ListMessageResponse) ListMessagesDigester.parse(soapListMessageResponse.toString()));
//			return ""+getListMessageResponse().getNoOfMessages()+" "+getListMessageResponse().getTotalSize() ;
//		}
//		if(foldersForStat.size() == 0){
//			// no folders found for stat
//			return null ;
//		}
		return null ;
	}

	/*
	public Set getSubscribedFolders() {
		return subscribedFolders;
	}


	public void setSubscribedFolders(Set subscribedFolders) {
		this.subscribedFolders = subscribedFolders;
	}*/


	public String getBaseURL() {
		return baseURL;
	}


	public void setBaseURL(String baseURL) {
		this.baseURL = baseURL;
	}


	public String getWssid() {
		return wssid;
	}


	public void setWssid(String wssid) {
		this.wssid = wssid;
	}


	public IListMessageResponse getListMessageResponse() {
		return listMessageResponse;
	}

	/*
	public void setListMessageResponse(ListMessageResponse listMessageResponse) {
		this.listMessageResponse = listMessageResponse;
	}

	public StringBuffer getHeadersFromSite(String mid, String folder){
//			 get the stat for each folder
		log.debug("baseUrl: "+getBaseURL());
		log.debug("wssid: "+getWssid());
		log.debug("kMsgHeaders: "+YahooPatterns.kMsgHeaders);
		URL url = null ;
		try {
			url = new URL(this.getBaseURL()+YahooPatterns.soapGetMessageRawHeader+wssid);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		String soapRequest = YahooPatterns.kMsgHeaders.replace("FOLDERNAME", folder);
		soapRequest = soapRequest.replace("MSGID", mid);
		log.debug("final soap req: "+soapRequest);
		NameValuePair [] requestParams = new NameValuePair[]{
				new NameValuePair("",soapRequest)};
		StringBuffer soapMessageHeaderResponse = HTTPConnection.getInstance().connect(url, requestParams, "POST","application/xml");
//		log.debug(soapMessageHeaderResponse.toString());
		return soapMessageHeaderResponse ;
	}*/

	public StringBuffer getMessage(int id) {
//		// find out mId and foldername for the message using the ListMessageResponse structure
//		ListMessageResponse listMessageResp = getListMessageResponse();
//		String mid = null ;
//		String folder = listMessageResp.getFolderName() ;
//		for (int i = 0 ; i < listMessageResp.getMessageList().size(); i++) {
//			if(i+1 == id){
//				MessageInfo message= (MessageInfo) listMessageResp.getMessageList().get(i);
//				mid = message.getMid();
//			}
//		}
//		log.debug("STAT mid: "+mid + " folder: "+folder);
//
//		StringBuffer sbHeaderResp = getHeadersFromSite(mid,folder);
//		// process the folder list
//		setRawHeaders((String) MessageHeaderDigester.parse(sbHeaderResp.toString()));
//		// above string is URL safe (escaped). make it to normal
//		setRawHeaders(NCRDecoder.decode(getRawHeaders()));
//		// add application specific headers
//		setEnvelopeHeaders(addEnvelopeHeaders(getRawHeaders(),folder));
//		// header must have \r\n for every EOL
//		setEnvelopeHeaders(formatText(getEnvelopeHeaders()));
//		log.debug("envelope headers: "+getEnvelopeHeaders());
//		
//		// get message body now..
//		URL url = null ;
//		try {
//			url = new URL(this.getBaseURL()+YahooPatterns.soapGetMessageBodyPart+wssid);
//		} catch (MalformedURLException e) {
//			e.printStackTrace();
//		}
//		String soapRequest = YahooPatterns.kMsgBody.replace("FOLDERNAME", folder);
//		soapRequest = soapRequest.replace("MSGID", mid);
//		log.debug("final soap req (MessageBody): "+soapRequest);
//		NameValuePair[] requestParams = new NameValuePair[]{
//				new NameValuePair("",soapRequest)};
//		StringBuffer soapMessageBodyResponse = HTTPConnection.getInstance().connect(url, requestParams, "POST","application/xml");
//		log.debug(soapMessageBodyResponse.toString());
//		
//		setMessage((Message) MessageBodyDigester.parse(soapMessageBodyResponse.toString()));
//		
//		// TODO Need to write code for marking mail as read on the server... Once RETR is successful, youo must send msg back to yahoo site statingthis msg is read.
//		
//		// process message
//		StringBuffer completeRawMessage = processMessage(getEnvelopeHeaders(), getMessage());
//		
////		return ""+getListMessageResponse().getNoOfMessages()+" "+getListMessageResponse().getTotalSize() ;
////		if(foldersForStat.size() == 0){
////			// no folders found for stat
////			return null ;
////		}
//		return completeRawMessage;		
		return null ;
	}

	/*private String formatText(String text) {
		StringBuilder sb = new StringBuilder(200);
		BufferedReader br = new BufferedReader(new StringReader(text));
		String line ;
		try {
			while((line = br.readLine() )!= null){
				sb.append(line+"\r\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		log.debug("formatted text: "+sb.toString());
		return sb.toString();
	}


	private StringBuffer processMessage(String envelopeHeader, Message message) {
		StringBuffer completeRawEmail = new StringBuffer(envelopeHeader);
        String boundrytext = getBoundryString(envelopeHeader);
        String startBoundary = null ;
        String endBoundary = null ;
        if( ! boundrytext.isEmpty()){
	        startBoundary = "\r\n--" + boundrytext + "\r\n";
	        endBoundary = "\r\n--" + boundrytext + "--\r\n\r\n";
        }
        
		for (Iterator iter = message.getParts().iterator(); iter.hasNext();) {
			MessagePart part = (MessagePart) iter.next();
            
			if(part.getText() != null){
				// format the text
				part.setText(formatText(part.getText()));
			}
			
            // TODO lot of code related to email building is needed here :-( out of my head right now
			// Referring this page: http://www.w3.org/Protocols/rfc1341/4_Content-Type.html
			if(part.getType().equalsIgnoreCase("text")){
    			String header = "";
    			if(! boundrytext.isEmpty()){
	    			header = "Content-Type: "+part.getType()+"/"+part.getSubtype()+"; " +part.getTypeParams() + "\r\n";
	                header += "Content-Transfer-Encoding: 7bit\r\n\r\n";
		            completeRawEmail.append(startBoundary);
    			}else{
    				header = "\r\n" ;
    			}
	            completeRawEmail.append(header);
	            completeRawEmail.append(part.getText());
            }else if(part.getType().equalsIgnoreCase("multipart")){
            	
            }else if(part.getType().equalsIgnoreCase("message")){
            	
            }else if(part.getType().equalsIgnoreCase("text")){
            	
            }else if(part.getType().equalsIgnoreCase("text")){
            	
            }else if(part.getType().equalsIgnoreCase("text")){
            	
            }else{
            	
            }
		}
		completeRawEmail.append(endBoundary);
		return completeRawEmail ;
	}

	private String getBoundryString(String header){
//		String contentType = (String) matcher("^Content-Type([\\s\\S]*?)$", new StringBuffer(header)).get(0);
//		log.debug(contentType );
		if(header.indexOf("boundary") == -1){
			log.debug("no boundry line.");
			return "";
		}
		String boundryLine = header.substring(header.indexOf("boundary"));
		boundryLine = boundryLine.substring(0,boundryLine.indexOf("\n"));
		if(boundryLine.indexOf("\"") == -1){
			boundryLine =boundryLine.substring(boundryLine.indexOf("=")+1);
			log.debug("no \" in the boundry line... : "+boundryLine);
		}else{
			boundryLine = boundryLine.substring(boundryLine.indexOf("\"")+1,boundryLine.lastIndexOf("\""));
		}
		log.debug("boundryLine :"+boundryLine );
		return boundryLine;
	}

	private String addEnvelopeHeaders(String rawHeaders, String folderName){
        return "X-WebMail: true\r\n" +
        	"X-Folder: " +folderName+ "\r\n"+rawHeaders;
	}
	
	public String getRawHeaders() {
		return rawHeaders;
	}


	public void setRawHeaders(String rawHeaders) {
		this.rawHeaders = rawHeaders;
	}


	public String getEnvelopeHeaders() {
		return envelopeHeaders;
	}


	public void setEnvelopeHeaders(String envelopeHeaders) {
		this.envelopeHeaders = envelopeHeaders;
	}


	public Message getMessage() {
		return message;
	}


	public void setMessage(Message message) {
		this.message = message;
	}


	public String getHeader(int id) {
		// find out mId and foldername for the message using the ListMessageResponse structure
		ListMessageResponse listMessageResp = getListMessageResponse();
		String mid = null ;
		String folder = listMessageResp.getFolderName() ;
		for (int i = 0 ; i < listMessageResp.getMessageList().size(); i++) {
			if(i+1 == id){
				MessageInfo message= (MessageInfo) listMessageResp.getMessageList().get(i);
				mid = message.getMid();
			}
		}
		log.debug("STAT mid: "+mid + " folder: "+folder);
		StringBuffer sbHeaderResp = getHeadersFromSite(mid, folder);
		// process the folder list
		setRawHeaders((String) MessageHeaderDigester.parse(sbHeaderResp.toString()));
		// above string is URL safe (escaped). make it to normal
		setRawHeaders(NCRDecoder.decode(getRawHeaders()));
		// add application specific headers
		setEnvelopeHeaders(addEnvelopeHeaders(getRawHeaders(),folder));
		// header must have \r\n for every EOL
		setEnvelopeHeaders(formatText(getEnvelopeHeaders()));
		return getEnvelopeHeaders();
	}
*/}
